package com.cherry.example.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
反射:一个class文件被加载到内存的时候，jvm马上会对该class文件进行解剖，解剖出该类的所有成员信息，
然后 jvm会创建一个Class对象把这些成员信息全部都封装起来，反射就是指我们获取 到该Class对象，那么
我们就可以通过该Class对象操作该类的所有成员。

提问：  接口，枚举，泛型类和 泛型接口，泛型方法如何反射？？？
*/
public class Demo1 {

    public static void main(String[] args) throws Exception {
        create();
        constructor();
        method();
        Class clazz = Class.forName("com.cherry.example.reflect.Person");

        //获取一个类的所有公共属性(包括了其父类的共有属性)
        Class claz = Class.forName("com.cherry.example.reflect.Teacher");
        Field[] fields = claz.getFields();
        for(Field field : fields){
            System.out.println(field);
        }
        //获取所有的成员（包括私有）。
		/*Field[]	 fields = clazz.getDeclaredFields();
		for(Field field : fields){
			System.out.println(field);
		}
		*/

        Person p = new Person("宁缺");
        //获取单个成员
        Field field =  clazz.getDeclaredField("name");
        field.setAccessible(true);
        //设置成员变量的值
        field.set(p, "皮皮");  // 参数一： 对象。   参数 二 ： 属性值。
        System.out.println(p);
    }

    private static void method() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Class clazz = Class.forName("com.cherry.example.reflect.Person");
		//获取一个类的所有公共方法(包括了其父类的方法)
//		Method[] methods = clazz.getMethods();
		//获取一个类的所有方法（包括私有方法），但是不包括父类的方法。
//		Method[] methods = clazz.getDeclaredMethods();
//		for(Method method: methods){
//			System.out.println(method);
//		}

//        Person p  = new Person(110,"狗娃");
        //获取单个的成员方法
		/*Method method = clazz.getDeclaredMethod("sleep", int.class); //参数一：方法名。   参数二： 形参的类型。
		//设置方法的访问权限。
		method.setAccessible(true);
		//执行方法。
		method.invoke(p, 2); //参数一：方法的调用者对象。    参数二： 方法所需要的参数。
*/

	/*
	    无参的方法反射
		Method method = clazz.getMethod("eat", null);
		method.invoke(p, null);
		*/

        //带返回值静态方法
        Method method =  clazz.getMethod("run", null);
        Boolean flag= (Boolean) method.invoke(null, null);
        System.out.println(flag);
    }

    private static void constructor() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException {
        Class clazz = Class.forName("com.cherry.example.reflect.Person");

	/*	//获取一个类的所有公共构造方法。
		//Constructor[] constructors = clazz.getConstructors();
		//获取一个类的所有构造方法
		Constructor[] constructors = clazz.getDeclaredConstructors();
		for(Constructor constructor : constructors){
			System.out.println(constructor);
		}

		获取单个构造方法
		Constructor constructor = clazz.getConstructor(int.class,String.class);
		//通过构造方法创建对象
		Person p = (Person) constructor.newInstance(110,"狗娃");
		System.out.println("对象的信息："+ p);
		*/

	    //私有构造方法实例化
        Constructor constructor = clazz.getDeclaredConstructor(null);
        //修改构造方法的访问权限。--暴力反射
        constructor.setAccessible(true);
        //使用无参的构造方法创建对象
        Person p = (Person) constructor.newInstance(null);
        System.out.println(p);
    }

    //	推荐使用： 第一种。 使用Class.forName方式。
    private static void create() throws ClassNotFoundException {
        //方式一： 可以通过Class.forName方式获取。
        Class clazz1 = Class.forName("com.cherry.example.reflect.Person");
        //方式二： 可以通过类名直接获取
        Class clazz2 = Person.class;
        //方式三：通过对象获取
		Class clazz3 = new Person("桑桑").getClass();
        System.out.println("clazz1与clazz2是同一个 对象吗？" + (clazz1 == clazz2));
        System.out.println("clazz2与clazz3是同一个 对象吗？" + (clazz3 == clazz2));
    }

}
